package server;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.xml.bind.JAXBException;

import pojo.SwingServerInformation;
import br.org.lh.ClientSwing.Utils.AppLevelContext;
import br.org.lh.ClientSwing.exceptions.ControllerNotFoundException;
import br.org.lh.global.core.XmlParser;
import br.org.lh.global.core.resources.actionBinding.Base;
import br.org.lh.global.core.resources.actionBinding.Controller;
import br.org.lh.global.exceptions.noJarPresent;

public class ServerPreLoader {

	private static final String baseDir = "resources";

	public static SwingServerInformation getSwingServerInformation(
			String filePath) throws IOException {
		try {
			byte[] byteArray = getFileAsByte(filePath);
			if (byteArray == null)
				return null;
			AppLevelContext appLevelContext = new AppLevelContext ();
			Integer JarConstant = getAppLevelContext(filePath,
					appLevelContext);
			return new SwingServerInformation(JarConstant, byteArray.length,
					byteArray, appLevelContext,filePath);
		} catch (ControllerNotFoundException e) {
			e.printStackTrace();
			return null;
		} catch (noJarPresent e) {
			e.printStackTrace();
			return null;
		}
	}

	private static byte[] getFileAsByte(String jarName) throws noJarPresent,
			IOException {
		try {
			File file = new File(getJarPathByName(jarName));
			if (file.length() > Integer.MAX_VALUE)
				return null;
			int length;
			FileInputStream fileInputStream = new FileInputStream(file);
			ByteArrayOutputStream out = new ByteArrayOutputStream((int) file
					.length());
			byte[] buf = new byte[(int) file.length()];
			while ((length = fileInputStream.read(buf)) > 0) {
				out.write(buf, 0, length);
			}
			return out.toByteArray();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			throw new noJarPresent();
		}

	}

	private static Integer getAppLevelContext(String jarName,
			AppLevelContext appLevelContext)
			throws ControllerNotFoundException, noJarPresent {
		Integer jarConstant = SwingServerInformation.CLIENTSWING;
		try {
			JarFile jarFile = getJarFile(jarName);
			JarEntry entry;
			if ((entry = (JarEntry) jarFile.getEntry("properties.xml")) != null)
				;
			List<Controller> controllerList = getControllerList(jarFile.getInputStream(entry));
			for (Controller controller : controllerList) {
				
				if ((entry = (JarEntry) jarFile.getEntry(controller.getPath())) == null) {
					if (controllerExistsOutsideJar(controller.getPath())) {
						jarConstant = SwingServerInformation.SERVERSWING;
						appLevelContext.setAppController(controller, true);
					} else
						throw new ControllerNotFoundException();
				} else {
					appLevelContext.setAppController(controller, false);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new noJarPresent("The specified jar cannot be found.");
		}
		return jarConstant;
	}
	
	private static JarFile getJarFile (String jarFilePath) throws noJarPresent{
		String jarPath = getJarPathByName(jarFilePath);
		JarFile jarFile = null;
		try {
			jarFile = new JarFile(jarPath);
		} catch (IOException e) {
			e.printStackTrace();
			throw new noJarPresent();
		}
		return jarFile;
	}

	private static boolean controllerExistsOutsideJar(String controllerPath) {
		try {
			Class.forName(controllerPath);
			return true;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return false;
		}

	}

	private static String getJarPathByName(String jarName) {
		return baseDir + File.separatorChar + jarName;
	}

	private static List<Controller> getControllerList(InputStream inputStream) {
		List<Controller> returnList = new LinkedList<Controller>();
		try {
			Base baseAction = XmlParser.parseActions(inputStream);
			for (Controller c : baseAction.getController())
				returnList.add(c);
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return returnList;
	}

}
